﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using AlgorithmBox.FlowCharts;
using AlgorithmBox.Classes;
using AlgorithmBox.Script;
using System.Windows.Media.Animation;
using System.IO;

//PM> Install-Package Roslyn.Compilers.CSharp -Version 1.1.20524.4 

namespace AlgorithmBox
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		#region Variables
		FlowChartElement currentElement = null;
		#endregion

		public MainWindow()
		{
			InitializeComponent();

		}

		private void Window_Loaded(object sender, RoutedEventArgs e)
		{
			//NativeMethods.ExtendGlass(this, new Thickness(700));
			flowChart.StartAnimation();

			//listVariables.Items.Add(new Variable());
		}

		private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
		{
			flowChart.CheckSelectedElement();

			flowChart.SetCanvasSize();
		}

		private void play_Toogled(object sender, RoutedEventArgs e)
		{
			if ((bool)startButton.IsChecked)
				StartAlgorithm();
			else
				StopAlgorithm();
		}

		private void ListBoxFlowChartElements_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			flowChart.IsDrawing = true;
			object selection = listBoxFlowElements.SelectedItem;// as FlowChartElement;

			if (selection is Process)
				flowChart.DrawingElement = new Process();
			else if (selection is Decision)
				flowChart.DrawingElement = new Decision();
			else if (selection is Connector)
				flowChart.DrawingElement = new ConnectionLine();
			else if (selection is Input)
				flowChart.DrawingElement = new Input();
		}

		AlgorithmExecuter executer = new AlgorithmExecuter();
		private void DeveloperConsole_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.Key == Key.Enter)
			{
				object result = executer.Run(textDeveloperConsole.Text);
				textConsoleIO.Items.Add(textDeveloperConsole.Text);
				textDeveloperConsole.Text = String.Empty;
				if (result != null)
					textConsoleIO.Items.Add(result.ToString());
				textConsoleIO.ScrollIntoView(textConsoleIO.Items[textConsoleIO.Items.Count-1]);
			}
		}

		private void UnSelectAll()
		{
			foreach (FlowChartElement fe in this.flowChart.Sketch.Children.OfType<FlowChartElement>())
				fe.IsSelected = false;
		}

		private void StartAlgorithm()
		{
			UnSelectAll();

			this.flowChart.StartFlow = this.flowChart.Sketch.Children.OfType<Start>().FirstOrDefault();
			if (flowChart.StartFlow.Link == null)
			{
				startButton.IsChecked = false;
				return;
			}

			startButton.Content = this.FindResource("stopButton");
			nextButton.IsEnabled = true;

			currentElement = this.flowChart.StartFlow.Link.Next;
			currentElement.IsSelected = true;
			textConsoleIO.Items.Clear();
			textConsoleIO.Items.Add(String.Format("Algortihm Started ({0})", DateTime.Now));
			executer.NewSession();
			defineVariables();

			AlgorithmExecuter.IsOn = true;
		}

		private void defineVariables()
		{
			foreach (Variable v in listVariables.Items.Cast<Variable>())
			{
				executer.Run(v.GetDefinition());
			}

			foreach (Input input in this.flowChart.Sketch.Children.OfType<Input>())
			{
				foreach (Variable v in listVariables.Items.Cast<Variable>())
				{
					if (input.Text == v.Name)
					{
						input.TypeConverter = GetVariableConverter(v.Type);
					}
				}
			}
		}

		private string GetVariableConverter(string type)
		{
			switch (type)
			{
				case "bool": return "Convert.ToBoolean";
				case "byte": return "Convert.ToByte";
				case "sbyte": return "Convert.ToSByte";
				case "short": return "Convert.ToInt16";
				case "ushort": return "Convert.ToUInt16";
				case "int": return "Convert.ToInt32";
				case "uint": return "Convert.ToUInt32";
				case "long": return "Convert.ToInt64";
				case "ulong": return "Convert.ToUInt64";
				case "float": return "Convert.ToSingle";
				case "double": return "Convert.ToDouble";
				case "decimal": return "Convert.ToDecimal";
				case "char": return "Convert.ToChar";
				case "string": return "Convert.ToString";
				default: return String.Empty;
			}
		}

		uint algorithmStep = 0;
		private void StopAlgorithm()
		{
			startButton.Content = this.FindResource("playButton");
			startButton.IsChecked = false;
			nextButton.IsEnabled = false;
			algorithmStep = 0;

			textConsoleIO.Items.Add(String.Format("Algortihm Finished ({0})", DateTime.Now));
			textConsoleIO.ScrollIntoView(textConsoleIO.Items[textConsoleIO.Items.Count-1]);

			AlgorithmExecuter.IsOn = false;
		}

		private void next_Clicked(object sender, RoutedEventArgs e)
		{
			if (currentElement is Stop)
			{
				StopAlgorithm();
				return;
			}
			object result = executer.Run(currentElement.Text);
			if (result != null)
				textConsoleIO.Items.Add(String.Format("{0}) {1}", ++algorithmStep, result));
			textConsoleIO.ScrollIntoView(textConsoleIO.Items[textConsoleIO.Items.Count-1]);

			if (currentElement is Decision)
			{
				Decision decision = (Decision)currentElement;
				decision.SetLink((bool)result);
			}

			if (currentElement.Link != null)
			{
				currentElement.IsSelected = false;
				currentElement = currentElement.Link.Next;
				currentElement.IsSelected = true;
			}
			else
			{
				StopAlgorithm();
			}
		}

		private void listBoxFlowElements_PreviewMouseDown(object sender, MouseButtonEventArgs e)
		{
			listBoxFlowElements.SelectedIndex = -1;
		}

		private void Save_Click(object sender, RoutedEventArgs e)
		{
			Microsoft.Win32.SaveFileDialog saveDiag = new Microsoft.Win32.SaveFileDialog();
			saveDiag.Filter = "Algorithm Box|*alb";

			if ((bool)saveDiag.ShowDialog())
				flowChart.SaveToFile(saveDiag.FileName, listVariables.Items.Cast<Variable>().ToList());

			//TextWriter w = new StreamWriter("C:\\deneme.xaml");
			//System.Windows.Markup.XamlWriter.Save(this.flowChart.Sketch, w);
			//MessageBox.Show(this.flowChart.Sketch.Children.Count.ToString());
			//w.Close();
		}

		private void Open_Click(object sender, RoutedEventArgs e)
		{
			Microsoft.Win32.OpenFileDialog openDiag = new Microsoft.Win32.OpenFileDialog();
			openDiag.Filter = "Algorithm Box|*alb";

			if ((bool)openDiag.ShowDialog())
			{
				flowChart.LoadFromFile(openDiag.FileName);
			}

			#region XAML Load
			//string xaml = File.ReadAllText("C:\\deneme.xaml");
			//xaml = System.Text.RegularExpressions.Regex.Replace(xaml, "Name=\"(.|\\n)*?\"", String.Empty);

			//StringReader r = new StringReader(xaml);
			//System.Xml.XmlReader xml = System.Xml.XmlReader.Create(r);
			//Canvas sk = (Canvas)System.Windows.Markup.XamlReader.Parse(xaml);
			//r.Close();
			//xml.Close();

			//List<UIElement> loadedElements = new List<UIElement>();

			//foreach (UIElement fl in sk.Children)
			//    loadedElements.Add(fl);

			//sk.Children.Clear();
			//this.flowChart.Sketch.Children.Clear();

			//foreach (UIElement fl in loadedElements)
			//    this.flowChart.Sketch.Children.Add(fl);

			//this.flowChart.StartAnimation();
			#endregion
		}

		public void EnumVisual(FrameworkElement myFE)
		{

			foreach (FrameworkElement childFE in LogicalTreeHelper.GetChildren(myFE).OfType<FrameworkElement>())
			{
				FrameworkElement element = myFE;
				if (!String.IsNullOrWhiteSpace(element.Name))
					try
					{
						System.Diagnostics.Debug.WriteLine(element.Name);
						this.flowChart.Sketch.UnregisterName(element.Name);
					}
					catch { }


				// Enumerate children of the child visual object. 
				EnumVisual(childFE);
			}
		}

		private void addNewVar_Click(object sender, RoutedEventArgs e)
		{
			listVariables.Items.Add(new Variable());
		}

		private void removeVar_Click(object sender, RoutedEventArgs e)
		{
			if (listVariables.SelectedIndex >= 0)
				listVariables.Items.RemoveAt(listVariables.SelectedIndex);
		}

	}

	//TODO: move to class file

	public class Variable
	{
		public string Name { get; set; }
		public string Type { get; set; }
		public int TypeIndex
		{
			get 
			{
				if (this.Type == null)
					return 0;
				string t = Char.ToUpper(this.Type[0])+this.Type.Substring(1, this.Type.Length-1);
				return (int)Enum.Parse(typeof(VarTypes), t);
			}
			set { }
		}

		char[] varSeparator = new char[1] { ',' };
		public string GetDefinition()
		{
			string[] data = this.Name.Split(varSeparator, StringSplitOptions.RemoveEmptyEntries);
			if (data.Length == 1)
				return String.Format("{0} {1};",
					this.Type.ToString().ToLower(),
					this.Name);
			
			
			int count = Convert.ToInt32(data[1]);
			return String.Format("{0}[] {1} = new {0}[{2}];",
				this.Type.ToString().ToLower(),
				data[0],
				data[1]);
		}
	}

	enum VarTypes
	{
		Bool,
		Byte,
		Sbyte,
		Short,
		Ushort,
		Int,
		Uint,
		Long,
		Ulong,
		Float,
		Double,
		Decimal,
		Char,
		String
	}
}
